#include <iostream>
#include <fstream>
#include <map>
#include <exception>

#include "point_in_polygon.hpp"
#include "json.hpp"

using json = nlohmann::json;

constexpr int MAX_POLYGON = 1000 * 1000;

// struct XLineString
// {
//     std::vector<double[2]> points;
// }

// struct XPolygon
// {
//     std::vector<XLineString> lineStrings;
// }

void load_polygon(const char *path, const Polygon **polygon)
{
    std::ifstream f;
    f.open(path);
    if (!f.is_open())
    {
        throw new std::runtime_error("file not exist");
    }
    char buf[MAX_POLYGON];
    f.read(buf, MAX_POLYGON);
    f.close();
    const auto j = json::parse(buf);
    const auto arr = j["lineStrings"];
    const auto lines = arr.get<std::vector<json::object_t>>();
    auto lineStrings = std::vector<LineString>();
    for (json::object_t line : lines)
    {
        const auto j = line["points"];
        const auto points = j.get<std::vector<std::vector<double>>>();
        // const auto lon = line["longitude"];
        // const auto lat = line["latitude"];
        auto arr = std::vector<Point>();
        for (auto vp : points)
        {
            const auto point = Point(vp[0], vp[1]);
            arr.push_back(point);
        }
        const auto lineString = LineString(arr);
        lineStrings.push_back(lineString);
    }
    *polygon = new Polygon(lineStrings);
    return;
}

const Polygon *polygon = nullptr;

int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        printf("USAGE: %s <polygon file> <point>\n", argv[0]);
        return 0;
    }
    try
    {
        const auto path = argv[1];
        load_polygon(path, &polygon);
        const auto pstr = argv[2];
        const auto j = json::parse(pstr);
        const auto lon = j["longitude"];
        const auto lat = j["latitude"];
        const auto point = Point(lon, lat);
        const auto b = polygon->containsPoint(point, false);
        std::cout << b << std::endl;
        return b ? 1 : 0;
    }
    catch (const std::exception &e)
    {
        std::cerr << "error: " << e.what() << std::endl;
        return 0;
    }
    catch (...)
    {
        std::cerr << "error: " << "unkown exception" << std::endl;
        return 0;
    }
}
